import { DefaultStage } from "../default-stage";
import { TransformNode } from "@babylonjs/core/Meshes/transformNode";
import { FreezeCamera } from "babylon-lib/misc/freeze-camera";
import { AbstractMesh, AnimationFrame, AnimationGroup, Scene } from "babylon-lib/index";
import { RawAssetsName, RawAssetsUrl } from "../../raw-assets-info";
import { Helper } from "babylon-lib/tool/helper";
import { PBRMaterial } from '@babylonjs/core/Materials/PBR/pbrMaterial';
import { RenderOrder } from "babylon-lib/misc/render-order";
import * as Data from '../../data/data';
import { AssetContainer, InstantiatedEntries } from "@babylonjs/core/assetContainer";


class Model {

    private static _req = {};
    private static _animation: AnimationGroup;
    private static _soldierAsset: AssetContainer;
    private static _instanceCount = 0;
    private static _scene: Scene;

    public static dixing: TransformNode;
    public static zhadan: TransformNode;
    public static shibing: TransformNode;
    public static wurenji: TransformNode;

    public static selectedTargetRight: TransformNode;
    public static selectedLocationRight: TransformNode;
    public static selectedTargetLeft: TransformNode;
    public static selectedLocationLeft: TransformNode;

    public static initialize(stage: DefaultStage): void {
        this._scene = stage.mainScene;
        this.dixing = stage.mainScene.getTransformNodeByName(RawAssetsName.dixing)!;
        this.zhadan = stage.mainScene.getTransformNodeByName(RawAssetsName.zhadan)!;
        const wurenji = stage.mainScene.getTransformNodeByName(RawAssetsName.wurenji)!;
        this.wurenji = new TransformNode('wurenji-model-container', stage.mainScene);
        wurenji.parent = this.wurenji;
        this.shibing = stage.mainScene.getTransformNodeByName(RawAssetsName.shibing)!;
        this._soldierAsset = this.initializeSoldierAssetContainer(stage);

        this.setTransform(stage);
        this.setMaterial(stage);
        this.bindData(stage);
    }

    public static reset(): void {
        AnimationFrame.cancel(this._req);
        this._animation.goToFrame(0);
        FreezeCamera.unfreeze();
    }

    private static bindData(stage: DefaultStage): void {
        const _this = Model;

    }

    public static getSoldierModel(): InstantiatedEntries {
        const _this = Model;
        const e1 = this._soldierAsset.instantiateModelsToScene((s) => { return s + _this._instanceCount++ }, false, { doNotInstantiate: true });
        e1.rootNodes.forEach(n => {
            Helper.getChildMeshes(n as TransformNode).forEach(m => {
                m.isVisible = true;
                m.alwaysSelectAsActiveMesh = true;
            });
        });
        return e1;
    }

    private static initializeSoldierAssetContainer(stage: DefaultStage): AssetContainer {
        const loader = stage.loader(stage.mainScene);
        const mt = loader.getMeshTaskInfo(RawAssetsUrl.modelShibing)!;
        mt.loadedAnimationGroups![0].stop();
        mt.loadedAnimationGroups![0].loopAnimation = true;
        mt.loadedMeshes?.forEach(m => m.isVisible = false);

        const ac = new AssetContainer(stage.mainScene);
        ac.animationGroups = mt?.loadedAnimationGroups!;
        ac.meshes = mt?.loadedMeshes!;
        ac.transformNodes = mt?.loadedTransformNodes!;
        ac.skeletons = mt!.loadedSkeletons!;
        return ac;
    }

    private static setTransform(stage: DefaultStage): void {
        const scn = stage.mainScene;
        this.dixing.scaling.set(1, 1, 1);
        this.dixing.position.set(0, 0, 0);
        scn.getMeshByName(RawAssetsName.groundMesh)!.renderingGroupId = RenderOrder.id(RenderOrder.baseName);
        const trees: AbstractMesh[] = [];
        Helper.nodeInArray(RawAssetsName.treeMesh, scn.meshes, trees, false);
        trees.forEach(m => m.renderingGroupId = RenderOrder.id(Data.orders.scene));

        this.wurenji.scaling.set(1, 1, 1);
        this.wurenji.position.set(10, 40, 0);
        Helper.getChildMeshes(this.wurenji).forEach(m => m.renderingGroupId = RenderOrder.id(Data.orders.scene));

        this.shibing.scaling.set(1, 1, 1);
        Helper.getChildMeshes(this.shibing).forEach(m => m.renderingGroupId = RenderOrder.id(Data.orders.scene));

        this.zhadan.scaling.set(1, 1, 1);
        this.zhadan.position.set(0, 95, 0);
        Helper.getChildMeshes(this.zhadan).forEach(m => m.renderingGroupId = RenderOrder.id(Data.orders.scene));
    }

    private static setMaterial(stage: DefaultStage): void {
        const texture = stage.loader(stage.mainScene).getCubeTextureTaskInfo(RawAssetsUrl.lightCubePX)?.texture!;
        [
            ...Helper.getChildMeshes(this.zhadan),
            ...Helper.getChildMeshes(this.shibing),
            ...Helper.getChildMeshes(this.wurenji),
        ].forEach(m => {
            const mat = m.material as PBRMaterial;
            mat.disableLighting = true;
        });
    }

}


export { Model };